package com.aruba.bubbleview;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.PointFEvaluator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Build;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.OvershootInterpolator;

/**
 * qq气泡
 */
public class BubbleView extends View {
    //原始气泡半径
    private int radius;
    //气泡颜色
    private int bubbleColor;
    private Paint bubblePaint = new Paint();
    //数字
    private String textNumber;
    //字体颜色
    private int textColor;
    //字体大小
    private int textSize;
    private Paint textPaint = new Paint();
    //气泡初始坐标
    private PointF bubblePoint = new PointF();
    //气泡移动坐标
    private PointF bubbleMovePoint = new PointF();
    //移动气泡和初始点的距离
    private int dst;
    //移动气泡最大距离
    private int maxDst;
    //气泡状态
    private int status;
    //静止状态
    private final static int status_bubble_default = 0;
    //连接状态
    private final static int status_bubble_connect = 1;
    //断开状态
    private final static int status_bubble_disconnect = 2;
    //消失状态
    private final static int status_bubble_dismiss = 3;
    //数字和气泡的间距
    private float padding;
    //触摸偏移
    private int offset = 100;

    public BubbleView(Context context) {
        this(context, null);
    }

    public BubbleView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public BubbleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(attrs);
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public BubbleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(attrs);
    }

    private void init(AttributeSet attrs) {
        TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.BubbleView);

        textNumber = typedArray.getString(R.styleable.BubbleView_textNumber);
        if (textNumber == null) textNumber = "0";

        bubbleColor = typedArray.getColor(R.styleable.BubbleView_bubbleColor, Color.RED);
        textColor = typedArray.getColor(R.styleable.BubbleView_textColor, Color.WHITE);
        padding = typedArray.getDimensionPixelSize(R.styleable.BubbleView_padding, 15);

        int textSize = typedArray.getDimensionPixelSize(R.styleable.BubbleView_textSize, dpToPx(14));
        setTextSize(textSize);

        bubblePaint.setAntiAlias(true);
        bubblePaint.setColor(bubbleColor);

        textPaint.setAntiAlias(true);
        textPaint.setColor(textColor);
    }

    public void initView(int x, int y) {
        bubblePoint.x = bubbleMovePoint.x = x;
        bubblePoint.y = bubbleMovePoint.y = y;

        status = status_bubble_default;
        invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (status != status_bubble_dismiss) {
            if (status == status_bubble_connect) {
                //画原始气泡，随距离变大，半径不断变小
                int initRadius = (int) (radius - dst / 8f);
                canvas.drawCircle(bubblePoint.x, bubblePoint.y, initRadius, bubblePaint);
                //画两条贝塞尔曲线
                int anchorX, anchorY, pathAX, pathAY, pathBX, pathBY, pathCX, pathCY, pathDX, pathDY;
                float sin = (bubbleMovePoint.y - bubblePoint.y) / (float) dst;
                float cos = (bubbleMovePoint.x - bubblePoint.x) / (float) dst;
                anchorX = (int) (bubblePoint.x + (bubbleMovePoint.x - bubblePoint.x) / 2);
                anchorY = (int) (bubblePoint.y + (bubbleMovePoint.y - bubblePoint.y) / 2);
                pathAX = (int) (bubblePoint.x - initRadius * sin);
                pathAY = (int) (bubblePoint.y + initRadius * cos);
                pathBX = (int) (bubbleMovePoint.x - (radius - 5) * sin);
                pathBY = (int) (bubbleMovePoint.y + (radius - 5) * cos);
                pathCX = (int) (bubbleMovePoint.x + (radius - 5) * sin);
                pathCY = (int) (bubbleMovePoint.y - (radius - 5) * cos);
                pathDX = (int) (bubblePoint.x + initRadius * sin);
                pathDY = (int) (bubblePoint.y - initRadius * cos);

                Path path = new Path();
                path.moveTo(pathAX, pathAY);
                path.quadTo(anchorX, anchorY, pathBX, pathBY);

                path.lineTo(pathCX, pathCY);
                path.quadTo(anchorX, anchorY, pathDX, pathDY);
                path.close();
                canvas.drawPath(path, bubblePaint);
            }

            //画文字
            Rect textRect = new Rect();
            textPaint.getTextBounds(textNumber, 0, textNumber.length(), textRect);
            Paint.FontMetrics m = new Paint.FontMetrics();
            textPaint.getFontMetrics(m);
            int baseLine = (int) (-(m.top + m.bottom) / 2);

            //画气泡
            RectF rectF = new RectF(textRect);
            if (textRect.height() > textRect.width()) {
                rectF.left -= (textRect.height() - textRect.width()) / 2;
                rectF.right += (textRect.height() - textRect.width()) / 2;
            }
            rectF.left -= padding;
            rectF.top -= padding;
            rectF.right += padding;
            rectF.bottom += padding;
            rectF.offset(bubbleMovePoint.x - textRect.width() / 2, bubbleMovePoint.y + textRect.height() / 2);

            radius = (int) (rectF.height() / 2);
            maxDst = radius * 8;
            canvas.drawRoundRect(rectF, radius, radius, bubblePaint);

            canvas.drawText(textNumber, bubbleMovePoint.x - textRect.width() / 2, bubbleMovePoint.y + baseLine, textPaint);
        }
    }

    /**
     * 设置文字字体大小
     *
     * @param textSize
     */
    public void setTextSize(int textSize) {
        this.textSize = textSize;
        textPaint.setTextSize(textSize);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN: {
                if (status != status_bubble_dismiss) {
                    dst = (int) Math.hypot(event.getX() - bubblePoint.x,
                            event.getY() - bubblePoint.y);

                    if (dst < offset) {//距离在点击触摸范围内，改变成连接状态
                        status = status_bubble_connect;
                        bubbleMovePoint.x = (int) event.getX();
                        bubbleMovePoint.y = (int) event.getY();
                        invalidate();
                    }
                }
                break;
            }
            case MotionEvent.ACTION_MOVE: {
                if (status != status_bubble_dismiss && status != status_bubble_default) {
                    dst = (int) Math.hypot(event.getX() - bubblePoint.x,
                            event.getY() - bubblePoint.y);

                    if (dst > maxDst - offset) {//距离大于最大距离，变为断开状态
                        status = status_bubble_disconnect;
                    }

                    bubbleMovePoint.x = (int) event.getX();
                    bubbleMovePoint.y = (int) event.getY();
                    invalidate();
                }
                break;
            }
            case MotionEvent.ACTION_UP: {
                if (status != status_bubble_dismiss && status != status_bubble_default) {

                    if (status == status_bubble_disconnect && dst > radius * 2) {//断开状态，并距离大于2倍的半径，消失
                        status = status_bubble_dismiss;
                    } else {//还原为默认状态
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                            startResetAnim();
                        } else {
                            bubbleMovePoint.x = bubblePoint.x;
                            bubbleMovePoint.y = bubblePoint.y;
                            status = status_bubble_default;
                        }
                    }

                    invalidate();
                }
                break;
            }
        }
        return true;
    }

    private ValueAnimator resetValueAnimator;

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private void startResetAnim() {
        resetValueAnimator = ValueAnimator.ofObject(new PointFEvaluator(), new PointF(bubbleMovePoint.x, bubbleMovePoint.y),
                new PointF(bubblePoint.x, bubblePoint.y));
        resetValueAnimator.setDuration(200);
        resetValueAnimator.setInterpolator(new OvershootInterpolator());
        resetValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                bubbleMovePoint = (PointF) animation.getAnimatedValue();
                postInvalidate();
            }
        });
        resetValueAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                bubbleMovePoint.x = bubblePoint.x;
                bubbleMovePoint.y = bubblePoint.y;
                status = status_bubble_default;
            }
        });

        resetValueAnimator.start();
    }

    public int dpToPx(int size) {
        final float scale = getContext().getResources().getDisplayMetrics().density;
        return (int) (size * scale + 0.5f);
    }
}
